package com.wu.store.controller;

import com.alibaba.fastjson.JSON;
import com.wu.store.common.util.MessageEntity;
import com.wu.store.dao.UserDao;
import com.wu.store.entity.GithubUser;
import com.wu.store.entity.User;
import com.wu.store.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.DigestUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@RestController
public class LoginController {

	@Autowired
	private Environment environment;

	@Autowired
	private UserService userService;

	@Autowired
	private UserController userController;

	@Autowired
	private UserDao userDao;

	@PostMapping("/login")
	public MessageEntity login(String username, String password) throws Exception {
		UsernamePasswordToken token = new UsernamePasswordToken(username, password);
		Subject currentUser = SecurityUtils.getSubject();
		Session session = currentUser.getSession(true);
		String message = "";
		try {
			currentUser.login(token);
		} catch (AuthenticationException e) {
			e.printStackTrace();
			User user = userDao.getUserByUserName(username);
			if (user == null) {
				message = "账号不存在";
			} else if (!user.getPassword().equals(DigestUtils.md5DigestAsHex(password.getBytes()))) {
				message = "密码不正确";
			} else {
				message = "登录失败";
			}
		} catch (Exception e) {
			e.printStackTrace();
			message = e.getMessage();
		}
		if (message.equals("")) {
			User user = (User) currentUser.getPrincipal();
			if (user.getIsAvailable() == 0) {
				throw new Exception("该账号不可用");
			}

			String timeout = environment.getProperty("session.timeout");
			session.setTimeout(Integer.parseInt(timeout));
			userService.updateUserCache(user);
			return new MessageEntity.Builder().success(true).data(user).message("登录成功").create();
		}
		return new MessageEntity.Builder().success(false).data(null).message(message).create();
	}

	@RequestMapping("/github")
	public void github(HttpServletResponse response, String code) throws Exception {
		RestTemplate restTemplate = new RestTemplate();
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
		LinkedMultiValueMap<String, String> map = new LinkedMultiValueMap<>();
		map.set("client_id", "1e747a3a685b71b46dd1");
		map.set("client_secret", "74de95d392d69be90f0b6c789c56134d14bc29db");
		map.set("code", code);

		HttpEntity<LinkedMultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
		String accessTokenResult = restTemplate.postForObject("https://github.com/login/oauth/access_token", request, String.class);
		//accessTokenResult 的返回值是以下这种格式
		//access_token=d48e25fbd7da2401e77d8b4f20374634013c54b4&scope=&token_type=bearer
		String[] items = StringUtils.split(accessTokenResult, "&");
		Map<String, String> accessMap = new HashMap<>();
		assert items != null;
		for (String item : items) {
			String[] keyVal = StringUtils.split(item, "=");
			String key = keyVal[0];
			String value = "";
			if (keyVal.length > 1) {
				value = keyVal[1];
			}
			accessMap.put(key, value);
		}
		String accessToken = accessMap.get("access_token");
		// {"login":"lifuzhao100","id":16594057,"node_id":"MDQ6VXNlcjE2NTk0MDU3","avatar_url":"https://avatars2.githubusercontent.com/u/16594057?v=4","gravatar_id":"","url":"https://api.github.com/users/lifuzhao100","html_url":"https://github.com/lifuzhao100","followers_url":"https://api.github.com/users/lifuzhao100/followers","following_url":"https://api.github.com/users/lifuzhao100/following{/other_user}","gists_url":"https://api.github.com/users/lifuzhao100/gists{/gist_id}","starred_url":"https://api.github.com/users/lifuzhao100/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lifuzhao100/subscriptions","organizations_url":"https://api.github.com/users/lifuzhao100/orgs","repos_url":"https://api.github.com/users/lifuzhao100/repos","events_url":"https://api.github.com/users/lifuzhao100/events{/privacy}","received_events_url":"https://api.github.com/users/lifuzhao100/received_events","type":"User","site_admin":false,"name":"lifuzhao","company":null,"blog":"","location":"广东 · 广州","email":null,"hireable":null,"bio":"be greater,be better","public_repos":8,"public_gists":0,"followers":3,"following":8,"created_at":"2016-01-07T13:39:25Z","updated_at":"2020-02-14T15:18:20Z"}
		String str = restTemplate.getForObject("https://api.github.com/user?access_token=" + accessToken, String.class);
		GithubUser userResponse = JSON.parseObject(str, GithubUser.class);
		assert userResponse != null;
		User githubUser = userDao.selectByAuthId("github", String.valueOf(userResponse.getId()));
		String username = "";
		String password = "";
		String redirectPath = "";
		if (githubUser == null) {
			// 首次登录跳转到用户信息页面
			redirectPath = "/#/user/info";
			password = UUID.randomUUID().toString();
			User user = setCommonUser(String.valueOf(userResponse.getId()), userResponse.getAvatarUrl(), password, str);
			user.setSource("github");
			trySave(user, userResponse.getName());
			username = user.getUsername();
		} else {
			// 非首次登录，跳转到首页
			redirectPath = "/";
			username = githubUser.getUsername();
			password = githubUser.getPassword();
		}
		login(username, password);
		response.sendRedirect(redirectPath);
	}

	@RequestMapping("weibo")
	public void weibo(HttpServletResponse response, String code) throws Exception {
		RestTemplate restTemplate = new RestTemplate();
		String redirectPath = "/#/login";
		if (StringUtils.isEmpty(code)) {
			response.sendRedirect(redirectPath);
		} else {
			HttpHeaders headers = new HttpHeaders();
			headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
			LinkedMultiValueMap<String, String> accessMap = new LinkedMultiValueMap<>();
			accessMap.set("client_id", "1702430832");
			accessMap.set("client_secret", "842183379ea19d902a4c38eb74055821");
			accessMap.set("grant_type", "authorization_code");
			accessMap.set("code", code);
//			accessMap.set("redirect_uri", "http://wuyixuan.xyz/weibo");
			accessMap.set("redirect_uri", "http://127.0.0.1:3001/weibo");
			HttpEntity<LinkedMultiValueMap<String, String>> accessEntity = new HttpEntity<>(accessMap, headers);
			Map accessRes = restTemplate.postForObject("https://api.weibo.com/oauth2/access_token", accessEntity, Map.class);
			assert accessRes != null;

			String accessToken = (String) accessRes.get("access_token");
			LinkedMultiValueMap<String, String> infoMap = new LinkedMultiValueMap<>();
			infoMap.set("access_token", accessToken);
			HttpEntity<LinkedMultiValueMap<String, String>> infoEntity = new HttpEntity<>(infoMap, headers);
			Map infoRes = restTemplate.postForObject("https://api.weibo.com/oauth2/get_token_info", infoEntity, Map.class);
			assert infoRes != null;
			String uid = String.valueOf(infoRes.get("uid"));
			User weiboUser = userDao.selectByAuthId("weibo", uid);
			String username = "";
			String password = "";
			if (weiboUser == null) {
				redirectPath = "/#/user/info";
				password = UUID.randomUUID().toString();
				User user = setCommonUser(uid, null, password, infoRes.toString());
				user.setSource("weibo");
				trySave(user, "weibo");
				username = user.getUsername();
			} else {
				redirectPath = "/";
				username = weiboUser.getUsername();
				password = weiboUser.getPassword();
			}
			login(username, password);
			response.sendRedirect(redirectPath);
		}
	}

	private User setCommonUser(String authId, String avatar, String password, String userInfo) {
		User user = new User();
		user.setGender(2);
		user.setAuthId(authId);
		user.setAvatar(avatar);
		user.setPassword(DigestUtils.md5DigestAsHex(password.getBytes()));
		user.setUserInfo(userInfo);
		user.setIsAvailable(1);
		user.setRole(2);
		user.setCreateTime(new Date());
		return user;
	}

	private void trySave(User user, String prefixName) {
		boolean isSuccess = false;
		while (!isSuccess) {
			try {
				String username = prefixName + "_" + UUID.randomUUID().toString().substring(0, 4);
				userService.validateIsUsernameValid(username, null);
				user.setUsername(username);
				userDao.addUser(user);
				isSuccess = true;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}
